package com.luyu.config;


import com.luyu.util.LuAuthenticationManager;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.token.*;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;

@Configuration
@EnableWebSecurity(debug = true)
@EnableMethodSecurity(proxyTargetClass = true)
public class SecurityConfig {

    private final String rememberMeKey = "123";

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder()
                .build();
    }

    // 跨域设置
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        source.registerCorsConfiguration("/**", config);
        return source;
    }

    @Bean
    public JWKSource<SecurityContext> jwkSource() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }


    @Bean
    public JwtEncoder jwtEncoder() {
        return new NimbusJwtEncoder(jwkSource());
    }

    @Bean
    public OAuth2TokenGenerator<?> tokenGenerator() {
        JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder());
        OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
        OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
        return new DelegatingOAuth2TokenGenerator(
                jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
    }


    // 自定义access token添加数据
    @Bean
    public OAuth2TokenCustomizer<JwtEncodingContext> jwtTokenCustomizer() {
        return (context) -> {
            if (OAuth2TokenType.REFRESH_TOKEN.equals(context.getTokenType())) {
                context.getClaims().claims((claims) -> {
                    claims.put("claim-1", "value-1");
                    claims.put("claim-2", "value-2");
                });
                // context.getJwsHeader().algorithm(SignatureAlgorithm.ES256);
            }
        };
    }


    // @Bean
    // public PersistentTokenRepository persistentTokenRepository(){
    //     return new InMemoryTokenRepositoryImpl();
    // }

    @Bean
    public RememberMeServices tokenBasedRememberMeServices(UserDetailsService userDetailsService) {
        return new TokenBasedRememberMeServices(rememberMeKey, userDetailsService);
    }


    @Bean
    public SecurityFilterChain luluSecurityFilterChain(HttpSecurity http,
                                                       JwtDecoder jwtDecoder,
                                                       LuAuthenticationManager luAuthenticationManager,
                                                       AccessDeniedHandler accessDeniedHandler,
                                                       AuthenticationEntryPoint authenticationEntryPoint,
                                                       UserDetailsService userDetailsService
    ) throws Exception {
        // 根据对应的config进行应用
        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
                new OAuth2AuthorizationServerConfigurer();


        http

                .headers(Customizer.withDefaults())
                .formLogin(AbstractHttpConfigurer::disable)
                .csrf(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(requestConfig -> {
                    requestConfig
                            .requestMatchers(AntPathRequestMatcher.antMatcher("/auth/login/access/token/**")).permitAll()
                            // .requestMatchers(endpointsMatcher).permitAll()
                            .anyRequest().authenticated()
                    ;
                })
                .oauth2ResourceServer(config -> {
                    config
                            .jwt(jwtConfigurer -> {
                                jwtConfigurer
                                        .decoder(jwtDecoder)

                                ;
                            })
                    ;
                })
                .exceptionHandling(exConfig -> {
                    exConfig
                            .accessDeniedHandler(accessDeniedHandler)
                            .authenticationEntryPoint(authenticationEntryPoint)
                    ;
                })
                .rememberMe(rememberMeConfig -> {
                    rememberMeConfig
                            .alwaysRemember(true)
                            .key(rememberMeKey)
                            .tokenValiditySeconds(2400000)
                            .rememberMeParameter("parameter")
                            //是否只允许开启https的cookie才能进行认证
                            .useSecureCookie(false)
                            // .rememberMeServices()
                            .rememberMeServices(tokenBasedRememberMeServices(userDetailsService))
                    ;

                })
                // .sessionManagement(sessionConfig->{
                //     sessionConfig
                //             //创建session策略
                //             .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                //             // 失效策略
                //             .invalidSessionStrategy(new RequestedUrlRedirectInvalidSessionStrategy())
                //             // 开启会话失效重定向
                //             .enableSessionUrlRewriting(true)
                //             // 会话失效重定向地址
                //             .invalidSessionUrl("https://www.baidu.com/")
                //             // session最大登陆数量
                //             .maximumSessions(5)
                //             // 会话过期行为
                //             // .expiredSessionStrategy()
                //             // 如果超过最大会话是否进行身份验证，并注销之前的会话给验证身份的会话使用
                //             .maxSessionsPreventsLogin(false)
                //             // session会话注册类
                //             .sessionRegistry(new RedisSessionRegistryImpl())
                //
                //
                //             ;
                // })
                .apply(authorizationServerConfigurer)
                .withObjectPostProcessor(new ManagerWithPostProcessor())
        ;
        http.cors(config -> config.disable());

        DefaultSecurityFilterChain chain = http.build();
        AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
        luAuthenticationManager.setManager(authenticationManager);
        RememberMeConfigurer configurer = http.getConfigurer(RememberMeConfigurer.class);
        System.out.println(configurer);
        return chain;
    }





}
